home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / C++ / DirectInput / ReadFFE / readffe.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-27  |  14.6 KB  |  446 lines

  1. //-----------------------------------------------------------------------------
  2. // File: ReadFFE.cpp
  3. //
  4. // Desc: DirectInput support to enumerate and play all effects in stored in a 
  5. //       DirectInput effects file.
  6. //
  7. // Copyright (c) Microsoft Corporation. All rights reserved.
  8. //-----------------------------------------------------------------------------
  9. #define STRICT
  10. #define DIRECTINPUT_VERSION 0x0800
  11.  
  12. #define SAFE_DELETE(p)       { if(p) { delete (p);     (p)=NULL; } }
  13. #define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p);   (p)=NULL; } }
  14. #define SAFE_RELEASE(p)      { if(p) { (p)->Release(); (p)=NULL; } }
  15.  
  16. #include <tchar.h>
  17. #include <windows.h>
  18. #include <commctrl.h>
  19. #include <basetsd.h>
  20. #include <commdlg.h>
  21. #include <dinput.h>
  22. #include "resource.h"
  23.  
  24.  
  25.  
  26.  
  27. //-----------------------------------------------------------------------------
  28. // Defines, constants, and global variables
  29. //-----------------------------------------------------------------------------
  30. struct EFFECTS_NODE
  31. {
  32.     LPDIRECTINPUTEFFECT pDIEffect;
  33.     DWORD               dwPlayRepeatCount;
  34.     EFFECTS_NODE*       pNext;
  35. };
  36.  
  37. LPDIRECTINPUT8        g_pDI       = NULL;         
  38. LPDIRECTINPUTDEVICE8  g_pFFDevice = NULL;
  39. EFFECTS_NODE          g_EffectsList;
  40.  
  41.  
  42.  
  43.  
  44. //-----------------------------------------------------------------------------
  45. // Function-prototypes
  46. //-----------------------------------------------------------------------------
  47. INT_PTR CALLBACK MainDialogProc( HWND, UINT, WPARAM, LPARAM );
  48. BOOL CALLBACK EnumFFDevicesCallback( LPCDIDEVICEINSTANCE pDDI, VOID* pvRef );
  49. BOOL CALLBACK EnumAndCreateEffectsCallback( LPCDIFILEEFFECT pDIFileEffect, VOID* pvRef );
  50.  
  51. HRESULT InitDirectInput( HWND hDlg );
  52. HRESULT FreeDirectInput();
  53. VOID    EmptyEffectList();
  54. HRESULT OnReadFile( HWND hDlg );
  55. HRESULT OnPlayEffects( HWND hDlg );
  56.  
  57.  
  58.  
  59.  
  60. //-----------------------------------------------------------------------------
  61. // Name: WinMain()
  62. // Desc: Entry point for the application.
  63. //-----------------------------------------------------------------------------
  64. int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, int )
  65. {
  66.     InitCommonControls();
  67.  
  68.     // Display the main dialog box.
  69.     DialogBox( hInst, MAKEINTRESOURCE(IDD_MAIN), NULL, MainDialogProc );
  70.  
  71.     return TRUE;
  72. }
  73.  
  74.  
  75.  
  76.  
  77. //-----------------------------------------------------------------------------
  78. // Name: MainDialogProc
  79. // Desc: Handles dialog messages
  80. //-----------------------------------------------------------------------------
  81. INT_PTR CALLBACK MainDialogProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
  82. {
  83.     HRESULT hr;
  84.  
  85.     switch( msg ) 
  86.     {
  87.         case WM_INITDIALOG:
  88.         {
  89.             // Set the icon for this dialog.
  90.             HICON hIcon = LoadIcon( (HINSTANCE)GetModuleHandle(NULL), 
  91.                                     MAKEINTRESOURCE( IDI_ICON ) );
  92.             PostMessage( hDlg, WM_SETICON, ICON_BIG,   (LPARAM)hIcon );  // Set big icon
  93.             PostMessage( hDlg, WM_SETICON, ICON_SMALL, (LPARAM)hIcon );  // Set small icon
  94.  
  95.             EnableWindow( GetDlgItem( hDlg, IDC_PLAY_EFFECTS ), FALSE );
  96.  
  97.             hr = InitDirectInput( hDlg );
  98.             if( FAILED(hr) )
  99.             {
  100.                 MessageBox( NULL, _T("Error Initializing DirectInput. ")
  101.                                   _T("The sample will now exit."),
  102.                                   _T("ReadFFE"), MB_ICONERROR | MB_OK );                
  103.                 EndDialog( hDlg, TRUE );
  104.             }
  105.             return TRUE;
  106.         }
  107.  
  108.         case WM_COMMAND:
  109.             switch( LOWORD(wParam) )
  110.             {
  111.                 case IDCANCEL:
  112.                     EndDialog( hDlg, FALSE ); 
  113.                     return TRUE;
  114.  
  115.                 case IDC_READ_FILE:
  116.                     if( FAILED( hr = OnReadFile( hDlg ) ) )
  117.                     {
  118.                         MessageBox( NULL, _T("Error reading effects file."),
  119.                                           _T("ReadFFE"), MB_ICONERROR | MB_OK );
  120.                         EnableWindow( GetDlgItem( hDlg, IDC_PLAY_EFFECTS ), FALSE );
  121.                     }
  122.                     return TRUE;
  123.  
  124.                 case IDC_PLAY_EFFECTS:
  125.                     if( FAILED( hr = OnPlayEffects( hDlg ) ) )
  126.                     {
  127.                         MessageBox( NULL, _T("Error playing DirectInput effects. ")
  128.                                           _T("The sample will now exit."), 
  129.                                           _T("ReadFFE"), MB_ICONERROR | MB_OK );
  130.                         EndDialog( hDlg, 1 );
  131.                     }
  132.                     return TRUE;
  133.             }
  134.             break;
  135.  
  136.         case WM_DESTROY:
  137.             FreeDirectInput();   
  138.             return TRUE;
  139.     }
  140.  
  141.     return FALSE;
  142. }
  143.  
  144.  
  145.  
  146.  
  147. //-----------------------------------------------------------------------------
  148. // Name: InitDirectInput()
  149. // Desc: Initialize the DirectInput variables.
  150. //-----------------------------------------------------------------------------
  151. HRESULT InitDirectInput( HWND hDlg )
  152. {
  153.     HRESULT hr;
  154.  
  155.     // Setup the g_EffectsList circular linked list
  156.     ZeroMemory( &g_EffectsList, sizeof( EFFECTS_NODE ) );
  157.     g_EffectsList.pNext = &g_EffectsList;
  158.  
  159.     // Create a DInput object
  160.     if( FAILED( hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, 
  161.                                          IID_IDirectInput8, (VOID**)&g_pDI, NULL ) ) )
  162.         return hr;
  163.  
  164.     // Get the first enumerated force feedback device
  165.     if( FAILED( hr = g_pDI->EnumDevices( 0, EnumFFDevicesCallback, 0, 
  166.                                          DIEDFL_ATTACHEDONLY | 
  167.                                          DIEDFL_FORCEFEEDBACK ) ) )
  168.         return hr;
  169.     
  170.     if( g_pFFDevice == NULL )
  171.     {
  172.         MessageBox( hDlg, _T("No force feedback device found.  ")
  173.                           _T("The sample will now exit."), 
  174.                           _T("ReadFFE"), MB_ICONERROR | MB_OK );
  175.         EndDialog( hDlg, 0 );
  176.         return S_OK;
  177.     }
  178.  
  179.     // Set the data format
  180.     if( FAILED( hr = g_pFFDevice->SetDataFormat( &c_dfDIJoystick ) ) )
  181.         return hr;
  182.  
  183.     // Set the coop level
  184.     if( FAILED( hr = g_pFFDevice->SetCooperativeLevel( hDlg, DISCL_EXCLUSIVE | 
  185.                                                              DISCL_BACKGROUND ) ) )
  186.         return hr;
  187.  
  188.     // Disable auto-centering spring
  189.     DIPROPDWORD dipdw;
  190.     dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
  191.     dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  192.     dipdw.diph.dwObj        = 0;
  193.     dipdw.diph.dwHow        = DIPH_DEVICE;
  194.     dipdw.dwData            = FALSE;
  195.  
  196.     if( FAILED( hr = g_pFFDevice->SetProperty( DIPROP_AUTOCENTER, &dipdw.diph ) ) )
  197.         return hr;
  198.  
  199.     // Acquire the device
  200.     if( FAILED( hr = g_pFFDevice->Acquire() ) )
  201.         return hr;
  202.  
  203.     return S_OK;
  204. }
  205.  
  206.  
  207.  
  208.  
  209. //-----------------------------------------------------------------------------
  210. // Name: EnumFFDevicesCallback()
  211. // Desc: Get the first enumerated force feedback device
  212. //-----------------------------------------------------------------------------
  213. BOOL CALLBACK EnumFFDevicesCallback( LPCDIDEVICEINSTANCE pDDI, VOID* pvRef )
  214. {
  215.     if( FAILED( g_pDI->CreateDevice( pDDI->guidInstance, &g_pFFDevice, NULL ) ) )
  216.         return DIENUM_CONTINUE; // If failed, try again
  217.  
  218.     // Stop when a device was successfully found
  219.     return DIENUM_STOP;
  220. }
  221.  
  222.  
  223.  
  224.  
  225. //-----------------------------------------------------------------------------
  226. // Name: FreeDirectInput()
  227. // Desc: Initialize the DirectInput variables.
  228. //-----------------------------------------------------------------------------
  229. HRESULT FreeDirectInput()
  230. {
  231.     // Release any DirectInputEffect objects.
  232.     if( g_pFFDevice ) 
  233.     {
  234.         EmptyEffectList();
  235.         g_pFFDevice->Unacquire();
  236.         SAFE_RELEASE( g_pFFDevice );
  237.     }
  238.  
  239.     // Release any DirectInput objects.
  240.     SAFE_RELEASE( g_pDI );
  241.  
  242.     return S_OK;
  243. }
  244.  
  245.  
  246.  
  247.  
  248. //-----------------------------------------------------------------------------
  249. // Name: EmptyEffectList()
  250. // Desc: Goes through the circular linked list and releases the effects, 
  251. //       and deletes the nodes
  252. //-----------------------------------------------------------------------------
  253. VOID EmptyEffectList()
  254. {
  255.     EFFECTS_NODE* pEffectNode = g_EffectsList.pNext;
  256.     EFFECTS_NODE* pEffectDelete;
  257.  
  258.     while ( pEffectNode != &g_EffectsList )
  259.     {
  260.         pEffectDelete = pEffectNode;       
  261.         pEffectNode = pEffectNode->pNext;
  262.  
  263.         SAFE_RELEASE( pEffectDelete->pDIEffect );
  264.         SAFE_DELETE( pEffectDelete );
  265.     }
  266.  
  267.     g_EffectsList.pNext = &g_EffectsList;
  268. }
  269.  
  270.  
  271.  
  272.  
  273. //-----------------------------------------------------------------------------
  274. // Name: OnReadFile()
  275. // Desc: Reads a file contain a collection of DirectInput force feedback 
  276. //       effects.  It creates each of effect read in and stores it 
  277. //       in the linked list, g_EffectsList.
  278. //-----------------------------------------------------------------------------
  279. HRESULT OnReadFile( HWND hDlg )
  280. {
  281.     HRESULT hr;
  282.  
  283.     static TCHAR strFileName[MAX_PATH] = TEXT("");
  284.     static TCHAR strPath[MAX_PATH] = TEXT("");
  285.     static TCHAR strSearch[MAX_PATH] = TEXT("");
  286.  
  287.     // Search around for directory of .ffe files
  288.     TCHAR strExePath[MAX_PATH] = {0};
  289.     TCHAR* strLastSlash = NULL;
  290.     GetModuleFileName( NULL, strExePath, MAX_PATH );
  291.     strExePath[MAX_PATH-1]=0;
  292.     strLastSlash = _tcsrchr( strExePath, TEXT('\\') );
  293.     if( strLastSlash )
  294.         *strLastSlash = 0;
  295.     wsprintf( strSearch, TEXT("%s\\bazooka.ffe"), strExePath );
  296.     if( GetFileAttributes( strSearch ) == 0xFFFFFFFF )
  297.     {
  298.         wsprintf( strSearch, TEXT("%s\\..\\bazooka.ffe"), strExePath );
  299.         if( GetFileAttributes( strSearch ) == 0xFFFFFFFF )
  300.         {
  301.             wsprintf( strSearch, TEXT("%s\\..\\..\\bazooka.ffe"), strExePath );
  302.             if( GetFileAttributes( strSearch ) == 0xFFFFFFFF )
  303.             {
  304.                 wsprintf( strSearch, TEXT("%s\\..\\ReadFFE\\bazooka.ffe"), strExePath );
  305.                 if( GetFileAttributes( strSearch ) == 0xFFFFFFFF )
  306.                 {
  307.                     wsprintf( strSearch, TEXT("%s\\bazooka.ffe"), strExePath ); 
  308.                 }
  309.             }
  310.         }
  311.     }
  312.     strLastSlash = _tcsrchr( strSearch, TEXT('\\') );
  313.     if( strLastSlash )
  314.         *strLastSlash = 0;
  315.  
  316.     // Setup the OPENFILENAME structure
  317.     OPENFILENAME ofn = { sizeof(OPENFILENAME), hDlg, NULL,
  318.                          TEXT("FEdit Files\0*.ffe\0All Files\0*.*\0\0"), NULL,
  319.                          0, 1, strFileName, MAX_PATH, NULL, 0, strSearch,
  320.                          TEXT("Open FEdit File"),
  321.                          OFN_FILEMUSTEXIST|OFN_HIDEREADONLY, 0, 0,
  322.                          TEXT(".ffe"), 0, NULL, NULL };
  323.  
  324.     if( '\0' == strPath[0] )
  325.     {
  326.         // Get the exe path
  327.         strLastSlash = NULL;
  328.         GetModuleFileName( NULL, strPath, MAX_PATH );
  329.         strPath[MAX_PATH-1]=0;
  330.         strLastSlash = _tcsrchr( strPath, TEXT('\\') );
  331.         if( strLastSlash )
  332.             *strLastSlash = 0;
  333.     }
  334.  
  335.     // Display the OpenFileName dialog. Then, try to load the specified file
  336.     if( FALSE == GetOpenFileName( &ofn ) )
  337.         return S_OK;
  338.  
  339.     EmptyEffectList();
  340.  
  341.     // Enumerate the effects in the file selected, and create them in the callback
  342.     if( FAILED( hr = g_pFFDevice->EnumEffectsInFile( strFileName, 
  343.                                                      EnumAndCreateEffectsCallback, 
  344.                                                      NULL, DIFEF_MODIFYIFNEEDED ) ) )
  345.         return hr;
  346.  
  347.     // Remember the path for next time
  348.     _tcscpy( strPath, strFileName );
  349.     strLastSlash = _tcsrchr( strPath, '\\' );
  350.     if( strLastSlash )
  351.         strLastSlash[0] = '\0';
  352.  
  353.     // If list of effects is empty, then we haven't been able to create any effects
  354.     if( g_EffectsList.pNext == &g_EffectsList )
  355.     {
  356.         // Pop up a box informing the user
  357.         MessageBox( hDlg, _T("Unable to create any effects."),
  358.                           _T("ReadFFE"), MB_ICONEXCLAMATION | MB_OK );
  359.         EnableWindow( GetDlgItem( hDlg, IDC_PLAY_EFFECTS ), FALSE );
  360.     }
  361.     else
  362.     {
  363.         // We have effects so enable the 'play effects' button
  364.         EnableWindow( GetDlgItem( hDlg, IDC_PLAY_EFFECTS ), TRUE );
  365.     }
  366.  
  367.     return S_OK;
  368. }
  369.  
  370.  
  371.  
  372.  
  373. //-----------------------------------------------------------------------------
  374. // Name: EnumAndCreateEffectsCallback()
  375. // Desc: Create the effects as they are enumerated and add them to the 
  376. //       linked list, g_EffectsList
  377. //-----------------------------------------------------------------------------
  378. BOOL CALLBACK EnumAndCreateEffectsCallback( LPCDIFILEEFFECT pDIFileEffect, VOID* pvRef )
  379. {   
  380.     HRESULT hr;
  381.     LPDIRECTINPUTEFFECT pDIEffect = NULL;
  382.  
  383.     // Create the file effect
  384.     if( FAILED( hr = g_pFFDevice->CreateEffect( pDIFileEffect->GuidEffect, 
  385.                                                 pDIFileEffect->lpDiEffect, 
  386.                                                 &pDIEffect, NULL ) ) )
  387.     {
  388.         OutputDebugString( TEXT("Could not create force feedback effect on this device.\n") );
  389.         return DIENUM_CONTINUE;
  390.     }
  391.  
  392.     // Create a new effect node
  393.     EFFECTS_NODE* pEffectNode = new EFFECTS_NODE;
  394.     if( NULL == pEffectNode )
  395.         return DIENUM_STOP;
  396.  
  397.     // Fill the pEffectNode up
  398.     ZeroMemory( pEffectNode, sizeof( EFFECTS_NODE ) );
  399.     pEffectNode->pDIEffect         = pDIEffect;
  400.     pEffectNode->dwPlayRepeatCount = 1;
  401.  
  402.     // Add pEffectNode to the circular linked list, g_EffectsList
  403.     pEffectNode->pNext  = g_EffectsList.pNext;
  404.     g_EffectsList.pNext = pEffectNode;
  405.  
  406.     return DIENUM_CONTINUE;
  407. }
  408.  
  409.  
  410.  
  411.  
  412. //-----------------------------------------------------------------------------
  413. // Name: OnPlayEffects()
  414. // Desc: Plays all of the effects enumerated in the file 
  415. //-----------------------------------------------------------------------------
  416. HRESULT OnPlayEffects( HWND hDlg )
  417. {
  418.     EFFECTS_NODE*       pEffectNode = g_EffectsList.pNext;
  419.     LPDIRECTINPUTEFFECT pDIEffect   = NULL;
  420.     HRESULT             hr;
  421.  
  422.     // Stop all previous forces
  423.     if( FAILED( hr = g_pFFDevice->SendForceFeedbackCommand( DISFFC_STOPALL ) ) )
  424.         return hr;
  425.  
  426.     while ( pEffectNode != &g_EffectsList )
  427.     {
  428.         // Play all of the effects enumerated in the file 
  429.         pDIEffect = pEffectNode->pDIEffect;
  430.  
  431.         if( NULL != pDIEffect )
  432.         {
  433.             if( FAILED( hr = pDIEffect->Start( pEffectNode->dwPlayRepeatCount, 0 ) ) )
  434.                 return hr;
  435.         }
  436.  
  437.         pEffectNode = pEffectNode->pNext;
  438.     }
  439.  
  440.     return S_OK;
  441. }
  442.  
  443.  
  444.  
  445.  
  446.